﻿using System;
using Reactor.Contracts;
using Spring.Context.Support;
using Spring.Objects.Factory.Config;
using Spring.Objects.Factory.Support;

namespace Reactor.Container.Spring
{
    public class SpringServiceRegistrar : IServiceRegistrar
    {
        private readonly GenericApplicationContext _applicationContext;

        /// <summary>
        /// Initializes a new instance of the <see cref="SpringServiceRegistrar"/> class.
        /// </summary>
        /// <param name="applicationContext">The application context.</param>
        public SpringServiceRegistrar(GenericApplicationContext applicationContext)
        {
            if (applicationContext == null) throw new ArgumentNullException("applicationContext");

            _applicationContext = applicationContext;
        }

        #region Implementation of IServiceRegistrar

        /// <summary>
        /// Registers a single instance that is to be returned when the specified type is requested..
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="instance">The instance.</param>
        public void RegisterInstance<T>(object instance) where T : class
        {
            _applicationContext.ObjectFactory.RegisterSingleton(typeof(T).FullName, instance);
        }

        /// <summary>
        /// Registers the a concrete type to associate with the abstract type.
        /// </summary>
        /// <typeparam name="T">Abstract type</typeparam>
        /// <typeparam name="TConcrete">The concrete type to instantiate when the abstract type is requested.</typeparam>
        public void RegisterType<T, TConcrete>() where TConcrete : T
        {
            IObjectDefinitionFactory objectDefinitionFactory = new DefaultObjectDefinitionFactory();
            var builder = ObjectDefinitionBuilder.RootObjectDefinition(objectDefinitionFactory, typeof(TConcrete));
            builder.SetAutowireMode(AutoWiringMode.AutoDetect);
            
            _applicationContext.RegisterObjectDefinition(typeof(T).FullName, builder.ObjectDefinition);
        }

        #endregion
    }
}
